import sys
from datetime import datetime

import can
import cantools
import os
from PyQt5.QtCore import QThread, pyqtSignal
from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QTreeWidget, QTreeWidgetItem, QPushButton, QHBoxLayout, QComboBox, QFileDialog, QMessageBox


class CanReceiverThread(QThread):
    message_received = pyqtSignal(object)

    def __init__(self, bus):
        super().__init__()
        self.bus = bus
        self.running = False

    def run(self):
        self.running = True
        while self.running:
            try:
                message = self.bus.recv(timeout=1.0)
                if message is not None:
                    self.message_received.emit(message)
            except Exception as e:
                print(f"Error receiving CAN message: {e}")

    def stop(self):
        self.running = False


class CanReceiver(QWidget):
    def __init__(self):
        super().__init__()
        self.initUI()
        self.bus = None
        self.receive_thread = None
        self.data_dict = {}  # 用于存储按 CAN ID 分类的数据
        self.db = None  # 初始化 DBC 数据库为 None

    def initUI(self):
        # 创建布局
        main_layout = QVBoxLayout()

        # 创建排序选项
        sort_layout = QHBoxLayout()
        self.sort_combo = QComboBox()
        # self.sort_combo.addItems(['Time Order', 'CAN ID'])
        # self.sort_combo.currentIndexChanged.connect(self.sort_data)
        # sort_layout.addWidget(self.sort_combo)

        # 添加 DBC 文件按钮
        self.add_dbc_button = QPushButton('Add DBC File')
        self.add_dbc_button.clicked.connect(self.add_dbc_file)
        sort_layout.addWidget(self.add_dbc_button)

        main_layout.addLayout(sort_layout)

        # 创建 TreeWidget 控件
        self.tree_widget = QTreeWidget()
        self.tree_widget.setColumnCount(5)
        self.tree_widget.setHeaderLabels(['Time', 'CAN ID', 'DLC', 'Data', 'Decoded Data'])
        main_layout.addWidget(self.tree_widget)

        # 创建开始和停止按钮
        button_layout = QHBoxLayout()
        self.start_button = QPushButton('Start Receiving')
        self.start_button.clicked.connect(self.start_receiving)
        button_layout.addWidget(self.start_button)

        self.stop_button = QPushButton('Stop Receiving')
        self.stop_button.clicked.connect(self.stop_receiving)
        self.stop_button.setEnabled(False)
        button_layout.addWidget(self.stop_button)

        main_layout.addLayout(button_layout)

        # 设置布局
        self.setLayout(main_layout)
        self.setWindowTitle('Pcan Message Receiver')
        self.setGeometry(300, 300, 800, 600)
        self.show()

    def start_receiving(self):
        try:
            self.start_receiving_flag = True
            self.start_button.setEnabled(False)
            self.stop_button.setEnabled(True)
            if self.bus is None:
                # 初始化 CAN 总线
                self.bus = can.interface.Bus(bustype='pcan', channel='PCAN_USBBUS1', bitrate=500000)
            self.receive_thread = CanReceiverThread(self.bus)
            self.receive_thread.message_received.connect(self.process_message)
            self.receive_thread.start()
        except Exception as e:
            QMessageBox.critical(self, "Error", f"Failed to start receiving: {e}")
            self.start_button.setEnabled(True)
            self.stop_button.setEnabled(False)
            self.start_receiving_flag = False

    def stop_receiving(self):
        try:
            self.start_receiving_flag = False
            self.start_button.setEnabled(True)
            self.stop_button.setEnabled(False)
            if self.receive_thread is not None:
                self.receive_thread.stop()
                self.receive_thread.wait()
        except Exception as e:
            QMessageBox.critical(self, "Error", f"Failed to stop receiving: {e}")

    def process_message(self, message):
        try:

            can_id = hex(message.arbitration_id)
            time_stamp = message.timestamp
            time_stamp = message.timestamp
            # 将时间戳转换为时分秒毫秒格式
            dt = datetime.fromtimestamp(time_stamp)
            formatted_time = dt.strftime("%H:%M:%S.%f")[:-3]  # 取前三位毫秒
            dlc = message.dlc
            data = ' '.join([f'{byte:02X}' for byte in message.data])
            # 如果 ID 已存在，覆盖原数据
            if can_id in self.data_dict:
                parent_item = self.data_dict[can_id]
                parent_item.setText(1, can_id)
                parent_item.setText(0, str(dt))
                parent_item.setText(2, str(dlc))
                parent_item.setText(3, data)
                if self.db:
                        decoded_data = self.db.decode_message(message.arbitration_id, message.data)
                        decoded_data_str = ', '.join([f'{key}: {value}' for key, value in decoded_data.items()])
                        # 创建子项
                        child_item = QTreeWidgetItem(parent_item)
                        child_item.setText(4, decoded_data_str)
                        parent_item.addChild(child_item)

                else:
                    if parent_item.childCount() > 0:
                        parent_item.removeChild(parent_item.child(0))
            else:
                # 创建父项
                parent_item = QTreeWidgetItem(self.tree_widget)
                parent_item.setText(1, can_id)
                parent_item.setText(0, str(dt))
                parent_item.setText(2, str(dlc))
                parent_item.setText(3, data)
                self.data_dict[can_id] = parent_item

                if self.db:

                        decoded_data = self.db.decode_message(message.arbitration_id, message.data)
                        decoded_data_str = ', '.join([f'{key}: {value}' for key, value in decoded_data.items()])
                        # 创建子项
                        child_item = QTreeWidgetItem(parent_item)
                        child_item.setText(4, decoded_data_str)
                        parent_item.addChild(child_item)


            self.sort_data()
        except Exception as e:
                    QMessageBox.warning(self, "错误", str(e))

    def sort_data(self):
        try:
            sort_option = self.sort_combo.currentText()
            if sort_option == 'Time Order':
                # 按插入顺序，这里暂时不做特殊处理，因为数据是按接收顺序添加的
                pass
            elif sort_option == 'CAN ID':
                self.tree_widget.sortItems(0, 0)  # 按 CAN ID 升序排序
        except Exception as e:
            QMessageBox.critical(self, "Error", f"Error sorting data: {e}")

    def add_dbc_file(self):
        try:
            # 暂停接收线程
            if self.receive_thread is not None and self.receive_thread.isRunning():

                self.receive_thread.stop()
                self.receive_thread.wait()
                self.start_button.setEnabled(True)


            file_path, _ = QFileDialog.getOpenFileName(self, "Select DBC File", "", "DBC Files (*.dbc)")
            if file_path:
                try:
                    self.db = cantools.database.load_file(file_path)
                except Exception as load_error:
                    QMessageBox.critical(self, "Error", f"Error loading DBC file: {load_error}")
                    return

            # # 恢复接收线程
            # if self.receive_thread is not None:
            #     self.tree_widget.clear()
            #     self.receive_thread = CanReceiverThread(self.bus)
            #     self.receive_thread.message_received.connect(self.process_message)
            #     self.receive_thread.start()

        except Exception as e:
            QMessageBox.critical(self, "Error", f"Error in add DBC file operation: {e}")

    def closeEvent(self, event):
        try:
            # 在程序关闭时关闭 CAN 总线
            if self.bus is not None:
                self.bus.shutdown()
            event.accept()
        except Exception as e:
            QMessageBox.critical(self, "Error", f"Error closing CAN bus: {e}")
            event.ignore()


if __name__ == '__main__':
    app = QApplication(sys.argv)
    receiver = CanReceiver()
    sys.exit(app.exec_())
